首先先用一個簡單的範例來帶大家了解甚麼是 標籤樣板字面值。
function showConsole(strings, arg1) {
console.log(strings, arg1);
}
const myName = '哈士奇';
`您好 ${myName} ,餐點已經準備好嚕!`
showConsole 這個函式會顯示接收到的字串以及參數。
下方也有定義好的變數,以及事先準備好的樣板字面值字串。
而所謂的標籤樣板字面值,就是
showConsole`您好 ${myName} ,餐點已經準備好嚕!`;
直接將 函式名稱接在樣板字面值之前
存檔執行以後呢~
這樣的原理到底是怎麼運作的呢?
這邊解釋一下,我們傳入第一個參數 strings
是由樣板字面值拆解而來的!
那麼拆解的規則就是依據我們在樣板字面值中的 ${}
作為分段點
所以可以看到這邊就被拆成了兩段,並且放入一個陣列中
另外,arg則是 ${}
所傳入的變數,如果現在樣板字面值中的變數有多個的話,也會傳入多個。
// 標籤樣板字面值
function showConsole(strings, arg1, arg2, arg3) {
console.log(strings, arg1, arg2, arg3);
}
const myName = '哈士奇';
showConsole`您好 ${myName} ,餐點已經準備好嚕! ${2} ${4}`;
眼尖的人可以發現,只要參數變多,我手動設定的arg變數也要跟著變多,但有時候就是不知道會傳幾個參數。
這個時候就要使用前面章節也使用過的其餘參數運算子(...),來盛裝這些傳入的參數內容!
// 標籤樣板字面值
function showConsole(strings, ...arg) {
console.log(strings, arg);
}
const myName = '哈士奇';
showConsole`您好 ${myName} ,餐點已經準備好嚕! ${2} ${4}`;
接下來我們就透過一個小範例來讓大家更了解要怎麼用運用 標籤樣板字面值!
情境: 我們現在希望得到一個組好的字串:
`您好 <span> 哈士奇 <span> ,餐點已經準備好嚕~!`
那我們剛剛依據所學得,先做出第一部的程式碼來看看~
const myName = '哈士奇';
const sentence = `您好 ${myName} ,餐點已經準備好嚕!`;
console.log(sentence);
那麼我們要針對變數加上 span 的標籤的話,就要使用標籤樣板字面值,為此我們得先定義一個函式。
const myName = '哈士奇';
const highlight = (strings, ...arg) =>(
strings.map((str, i) => `${str}`)
);
const sentence = highlight`您好 ${myName} ,餐點已經準備好嚕!`;
console.log(sentence);
定義好之後,我們針對 strings 進行 map 的迴圈,最後會回傳一個新的陣列。
並且先把 str 印出來,看看是不是被拆解的字串
很好,如我們預期的,只有先是字串的陣列,那麼這個時候我們再使用join,將陣列轉為字串,同時去除掉逗號。
const myName = '哈士奇';
const highlight = (strings, ...arg) =>(
strings.map((str, i) => `${str}`).join('')
);
const sentence = highlight`您好 ${myName} ,餐點已經準備好嚕!`;
console.log(sentence);
到這邊已經準備得差不多,字串也組好了!
接著下一步就是加入傳入的變數!
const myName = '哈士奇';
const highlight = (strings, ...arg) =>(
strings.map((str, i) => `${str} <span>${arg[i]}</span>`).join('')
);
const sentence = highlight`您好 ${myName} ,餐點已經準備好嚕!`;
console.log(sentence);
只差一點點了,為什麼最後面會出現 undefined 呢?
原因是因為,strings 的陣列有兩個內容,但是 arg 的陣列只有一個參數傳入,所以當他找 arg[1]
的時候取不到值,只好回傳 undefind。
這個時候該怎麼半呢?
這個時候我們就可以透過 三元運算子 來判斷這個值存不存在!
const myName = '哈士奇';
const highlight = (strings, ...arg) =>(
strings.map((str, i) => `${str} ${arg[i] ? `<span>${arg[i]}</span>` : '' }`).join('')
);
const sentence = highlight`您好 ${myName} ,餐點已經準備好嚕!`;
console.log(sentence);
這樣子就可以完成我們想要的結果嚕!
你可能會想說,為什麼需要這麼麻煩,一開始加上去不就好了嗎?
的確是這樣沒錯,但當變數一多的時候,直接套用就會比較方便喔!
現在我們是一個應用程式的開發者,現在有很多使用者會來傳入訊息。
const messageName = '小明';
document.querySelector('#message').innerHTML = `<p>${messageName}</p>傳來一則訊息!`
但是這樣的情況很容易造成 XSS 攻擊,簡單來說就是透過自定義的內容插入一些惡意的js程式,竊取用戶的個資或其他非開發者預期的行為。
// const messageName = '小明';
const messageName = '<img onload="fetch(\'https://randomuser.me/api/\')" src="https://images.unsplash.com/photo-1587613842352-3022a317a088?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80" alt=""/>'
document.querySelector('#message').innerHTML = `<p>${messageName}</p>傳來一則訊息!`
原本應該是出現人名的地方卻傳來了一張圖片!
更可怕的是使用 onload的屬性,有可能使用ajax或是把資料傳送給第三方的網站。
這個時候我們就可以使用標籤樣板字面值來把因為變數傳進來的有惡意的字串給換掉,防止XSS 攻擊
function convertHTMLXSS(strings, ...keys) {
return strings.map((str, i) => (
`${str}${keys[i] ? `${keys[i]
.replace(/&/g, '&')
.replace(/</g, '<')
.replace(/>/g, '>')
.replace(/"/g, '"')
.replace(/'/g, ''')
.replace(/\//g, '/')
}` : ''}`
)).join('');
}
const messageName = '<img onload="fetch(\'https://randomuser.me/api/\')" src="https://images.unsplash.com/photo-1587613842352-3022a317a088?ixlib=rb-1.2.1&ixid=eyJhcHBfaWQiOjEyMDd9&auto=format&fit=crop&w=634&q=80" alt=""/>'
document.querySelector('#message').innerHTML = convertHTMLXSS`<p>${messageName}</p>傳來一則訊息!`
以上就是標籤樣板字面值的介紹,沒有問題的話大家也可以試著想想看哪裡可以應用到標籤樣板字面值喔!
沒問題的話就繼續往下個章節吧~汪汪~!